function fitting = FitWorkingPoint(~, data, varargin)
    p=inputParser;
    p.addRequired('mode', @(x) ismember(x, {'PhaseRaw', 'PhaseFine', 'Bias'}));
    p.parse(varargin{:});
    
    switch p.Results.mode
        case 'PhaseRaw'
            [fitting.phase0, fitting.result, fitting.gof] = swpPhaseFitting(data);
        case 'PhaseFine'
            [fitting.phase0, fitting.residual, fitting.model, fitting.result, fitting.gof] = swpPhaseFineFitting(data);
        case 'Bias'
            [fitting.slope, fitting.zeropoint, fitting.result, fitting.gof] = swpSlopeFitting(data);
    end
end


function [phase0, fitresult, gof] = swpPhaseFitting(swprResult)
    data = swprResult.getNodeData(1); 
    [xData, yData] = prepareCurveData(data.x, data.y);

    amp = max(data.y); [~, idx] = min(data.y); phi0 = data.x(idx);
    % Set up fittype and options.
    ft = fittype( 'abs(A*sin(x/180*pi-phi)+B)', 'independent', 'x', 'dependent', 'y' );
    opts = fitoptions( 'Method', 'NonlinearLeastSquares' );
    opts.Display = 'Off';
    opts.Lower =      [amp*0.5 0 0];
    opts.StartPoint = [amp     0 phi0/180*pi];
    opts.Upper =      [amp*1.5 0 2*pi];

    % Fit model to data.
    [fitresult, gof] = fit( xData, yData, ft, opts );
    phase0 = fitresult.phi/pi*180;
end

function [phase0, residual, model, fitresult, gof] = swpPhaseFineFitting(swprResult)
    data = swprResult.getNodeData(1);
    [xData, yData] = prepareCurveData(data.x, data.y.^2);
    
    ft = fittype( 'poly2' );
    excludedPoints = excludedata( xData, yData, 'Indices', 1);
    opts = fitoptions( );
    opts.Exclude = excludedPoints;
    [fitresult, gof] = fit( xData, yData, ft, opts );
    phase0 = -fitresult.p2/2.0/fitresult.p1;
    
    minVal = fitresult.p3 - fitresult.p2^2/4.0/fitresult.p1;
    if minVal >= 0.0
        residual = sqrt(minVal);
        model = 'poly2';
    else
        [xData, yData] = prepareCurveData(data.x, data.y);
        ft1 = fittype( 'a*abs(x-x0)+b', 'independent', 'x', 'dependent', 'y' );
        opts = fitoptions( 'Method', 'NonlinearLeastSquares' );
        opts.Display = 'Off';
        opts.StartPoint = [sqrt(fitresult.p1), 0.0, phase0];
        opts.Lower = [0 0 0];
        excludedPoints = excludedata( xData, yData, 'Indices', 1);
        opts.Exclude = excludedPoints;
        [fitresult, gof] = fit( xData, yData, ft1, opts );
        
        phase0 = fitresult.x0; residual = fitresult.b;
        model = 'abs';
    end
end

function [slope,zeropoint, result, gof] = swpSlopeFitting(swprResult)
    data = swprResult.getNodeData(1);
    [xData, yData] = prepareCurveData( data.x, data.y );

    ft = fittype( 'poly1' );
    opts = fitoptions( 'Method', 'LinearLeastSquares' );

    [result, gof] = fit( xData, yData, ft, opts );
    slope = result.p1;
    zeropoint = -result.p2./result.p1;
end